#include <iostream>

using std::cout;
using std::endl;

class Data{
public:
    Data(int data=0)
    : _data(data)
    {
        cout<<"构造1"<<endl;
    }

    Data(const Data &rhs)
    : _data(rhs._data)
    {
        cout<<"拷贝1"<<endl;
    }

    int getData(){
        return _data;
    }

    ~Data(){
        cout<<"析构1"<<endl;
    }
    
private:
    int _data;
};

class Second{
public:
    Second(Data *pdata)
    : _pdata(pdata)
    {
        cout<<"构造2"<<endl;
    }

    Second(const Second &rhs)
    : _pdata(new Data())
    {
        cout<<"拷贝2"<<endl;
        _pdata=rhs._pdata;
    }

    Data *operator->(){
        return _pdata;
    }

/*
    Data operator->(){
        return *_pdata;
    }
    
    这样写相当于返回 _pdata的解引用，即直接返回了一个Data，多调用一次拷贝构造函数
    那么下面调用时也要改成
    cout<<s2.operator->().getData()<<endl;
*/
    ~Second(){
        cout<<"析构2"<<endl;
        if(_pdata){
            delete _pdata;
            _pdata=nullptr;
        }
    }
private:
    Data *_pdata;
};

class Third{
public:
    Third(Second *psl)
    : _psl(psl)
    {
        cout<<"构造3"<<endl;
    }
/*
    Second *operator->(){
        return _psl;
    }
    如果这里写成和第二层一样，则
    error: ‘class Second’ has no member named ‘getData’
    cout<<s3->getData()<<endl;
    无法跨层 
    
    如果硬要写，则下面这么调用
    cout<<s3.operator->()->operator->()->getData()<<endl;
*/

    Second &operator->(){
        return *_psl;
    }
    //如果不加&，则运行时报错二次释放
    //原因如下：
    //此时返回的是一个Second临时对象，调用Second的拷贝构造函数，
    //参数为 _psl，注意这个 _psl是真正的指向我们的Second的_psl
    //而在拷贝函数内部，会将临时对象的_pdata指向 真psl里的_pdata所指向Data
    //那么在释放临时对象时，会先把真正的Data空间释放掉了（通过临时对象的_pdata）
    //之后程序结束，释放Third的真_psl时，会把这个Data又释放一遍
    //问题出在了第一层

    ~Third(){
        cout<<"析构3"<<endl;
        if(_psl){
            delete _psl;
            _psl=nullptr;
        }
    }
private:
    Second *_psl;
};

void test(){
    Second s2(new Data(10));
    cout<<s2->getData()<<endl;
    //cout<<s2.operator->()->getData()<<endl;

    //s2本身是一个栈对象，但能像指针一样去调用->函数
    //而且Second本身并没有getData()函数
}

void test2(){
    Third s3(new Second(new Data(100)));
    //cout<<s3.operator->()->operator->()->getData()<<endl;
    
    cout<<s3->getData()<<endl;
    //cout<<s3.operator->().operator->()->getData()<<endl;
    // 注意Third的重载函数里返回的是引用，而不是指针 
    
    //s3和s2本身不是指针对象，仍是堆对象，会自动析构
    //但s2和s3可以像指针一样使用
}

int main()
{   
    test2();
    return 0;
}

